//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
// 

#include "outer.h"

Define_Module(Outer);


void Outer::initialize()
{
    // 若开机则发送self_packet
    if (par("outer_enable").boolValue() == true)
    {
        cMessage *self_packet = new cMessage("self_packet");
        scheduleAt(0, self_packet);
    }

    // 每个Adie的坐标值
    A_dies = {
            {0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11},{0,12},{0,13},{0,14},{0,15},
            {17,2},{17,3},{17,4},{17,5},{17,6},{17,7},{17,8},{17,9},{17,10},{17,11},{17,12},{17,13},{17,14},{17,15},
            {2,0},{3,0},{4,0},{5,0},{6,0},{7,0},{8,0},{9,0},{10,0},{11,0},{12,0},{13,0},{14,0},{15,0},
            {2,17},{3,17},{4,17},{5,17},{6,17},{7,17},{8,17},{9,17},{10,17},{11,17},{12,17},{13,17},{14,17},{15,17},
    };

    // 初始化统计信号
    latencySingal = registerSignal("latency_reg");
    sendSingal = registerSignal("send_reg");
    recvSingal = registerSignal("recv_reg");
    sendBitSingal = registerSignal("sendBit_reg");
    recvBitSingal = registerSignal("recvBit_reg");
    hopSingal = registerSignal("hop_reg");
    sendTimeSingal = registerSignal("sendTime_reg");
    recvTimeSingal = registerSignal("recvTime_reg");

    latency = 0;
    send_packet_num = 0;
    recv_packet_num = 0;
    bitLengthSend = 0;
    bitLengthRecv = 0;
    hop = 0;
    sendTime = 0;
    recvTime = 0;

    // 160Gpbs
    DELAY = 6.25e-12;
}

void Outer::handleMessage(cMessage *msg)
{
    // 若发现是self_packet，则进行发包操作
    if (strcmp(msg->getName(), "self_packet") == 0)
    {
        // 删除取消self_packet
        cancelAndDelete(msg);
        Packet *packet_tobesent = generateMessage();

        // 发送2000个数据包进行测试
        // if (send_packet_num < 2000000)
        if (send_packet_num < 200000)
        {
            // 获取发送包的包长并emit
            bitLengthSend = packet_tobesent->getField();
            emit(sendBitSingal, bitLengthSend);
            // 将包的hop加一
            packet_tobesent->setHopcnt(packet_tobesent->getHopcnt() + 1);
            // 发送数据包
            // outer向die发送数据时应有delay
            //sendDelayed(packet_tobesent, 8 * bitLengthSend * DELAY, "outer_port$o");
            send(packet_tobesent, "outer_port$o");
            // 发包数量加一，并emit
            send_packet_num++;
            emit(sendSingal, send_packet_num);
            // 记录发包的时间
            sendTime = simTime();
            emit(sendTimeSingal, sendTime);

            // 按照一定的速率发送self_packet，重新开始下一轮发包
            cMessage *self_packet = new cMessage("self_packet");
            scheduleAt(simTime() + bitLengthSend * 8 * par("send_interval").doubleValue(), self_packet);
        }

        // 换为一直发包，定时停止
        /*bitLengthSend = packet_tobesent->getField();
        emit(sendBitSingal, bitLengthSend);
        // 将包的hop加一
        packet_tobesent->setHopcnt(packet_tobesent->getHopcnt() + 1);
        // 发送数据包
        // outer向die发送数据时应有delay
        sendDelayed(packet_tobesent, 8 * bitLengthSend * DELAY, "outer_port$o");
        // send(packet_tobesent, "outer_port$o");
        // 发包数量加一，并emit
        send_packet_num++;
        emit(sendSingal, send_packet_num);
        // 记录发包的时间
        sendTime = simTime();
        emit(sendTimeSingal, sendTime);

        // 按照一定的速率发送self_packet，重新开始下一轮发包
        cMessage *self_packet = new cMessage("self_packet");
        scheduleAt(simTime() + bitLengthSend * 8 * par("send_interval").doubleValue(), self_packet);*/
    }
    // 若发现是普通包
    else
    {
        // 接收包数量加一，并emit
        recv_packet_num++;
        emit(recvSingal, recv_packet_num);

        Packet *packet_rcvd = check_and_cast<Packet *>(msg);
        packet_rcvd->setArrive_time(simTime());

        // 计算包时延，并emit
        latency = packet_rcvd->getArrive_time() - packet_rcvd->getSend_time();
        emit(latencySingal, latency);
        // 计算接收到包的大小，并emit
        bitLengthRecv = packet_rcvd->getField();
        emit(recvBitSingal, bitLengthRecv);
        // 计算接收到包的hop，并emit
        hop = packet_rcvd->getHopcnt();
        emit(hopSingal, hop);
        // 计算接收到包的时间，并emit
        recvTime = simTime();
        emit(recvTimeSingal, recvTime);

        // bubble一下
        bubble("received msg!");
        delete msg;
    }
}

Packet *Outer::generateMessage()
{
    // 获取节点的xy坐标值
    int self_x = par("x").intValue();
    int self_y = par("y").intValue();

    // 生成uniform_random模式的数据包
    if (strcmp(par("send_mode"),"uniform_random") == 0)
    {
        EV << "entering uniform_random" << endl;
        Packet *outer_packet = new Packet("outer_packet");

        // 随机均匀获取目的节点坐标
        int dst_random_int = intuniform(0,A_dies.size()-1);
        int dst_random_x = A_dies[dst_random_int][0];
        int dst_random_y = A_dies[dst_random_int][1];

        /*int dst_random_x = 3;
        int dst_random_y = 0;*/

        int l_hopcnt = 0;
        //int l_field = intuniform(0,1500);
        int l_field = 300;

        // 设置packet的属性
        outer_packet->setSend_time(simTime());
        outer_packet->setSrc_x(self_x);
        outer_packet->setSrc_y(self_y);
        outer_packet->setDst_x(dst_random_x);
        outer_packet->setDst_y(dst_random_y);
        outer_packet->setHopcnt(l_hopcnt);
        outer_packet->setField(l_field);

        return outer_packet;
    }
    // 生成LTR模式的数据包
    else if (strcmp(par("send_mode"),"LTR") == 0)
    {
        // 设置01之间的随机数
        double a = uniform(0, 1);

        int dest_num_x = -1;
        int dest_num_y = -1;

        Packet *outer_packet = new Packet("outer_packet");

        outer_packet->setSrc_x(self_x);
        outer_packet->setSrc_y(self_y);
        outer_packet->setSend_time(simTime());

        // 有ltr_rate的包落在发送节点的周围
        if (a < par("ltr_rate").doubleValue())
        {
            // 最左侧的Adie
            if ((self_x == 0) and (self_y <= 15) and (self_y >= 2))
            {
                dest_num_x = 0;
                if (self_y == 2) // 边界情况
                {
                    dest_num_y = rand()%2 + 2;
                }
                else if (self_y == 15) // 边界情况
                {
                    dest_num_y = rand()%2 + 14;
                }
                else // 一般情况
                {
                    dest_num_y = (self_y + (rand()%3 - 1) + 16) % 16;
                }
            }
            // 最右侧的Adie
            else if ((self_x == 17) and (self_y <= 15) and (self_y >= 2))
            {
                dest_num_x = 17;
                if (self_y == 2) // 边界情况
                {
                    dest_num_y = rand()%2 + 2;
                }
                else if (self_y == 15) // 边界情况
                {
                    dest_num_y = rand()%2 + 14;
                }
                else // 一般情况
                {
                    dest_num_y = (self_y + (rand()%3 - 1) + 16) % 16;
                }
            }
            // 最上侧的Adie
            else if ((self_y == 0) and (self_x <= 15) and (self_x >= 2))
            {
                dest_num_y = 0;
                if (self_x == 2) // 边界情况
                {
                    dest_num_x = rand()%2 + 2;
                }
                else if (self_x == 15) // 边界情况
                {
                    dest_num_x = rand()%2 + 14;
                }
                else // 一般情况
                {
                    dest_num_x = (self_x + (rand()%3 - 1) + 16) % 16;
                }
            }
            // 最下侧的Adie
            else if ((self_y == 17) and (self_x <= 15) and (self_x >= 2))
            {
                dest_num_y = 17;
                if (self_x == 2) // 边界情况
                {
                    dest_num_x = rand()%2 + 2;
                }
                else if (self_x == 15) // 边界情况
                {
                    dest_num_x = rand()%2 + 14;
                }
                else // 一般情况
                {
                    dest_num_x = (self_x + (rand()%3 - 1) + 16) % 16;
                }
            }

            int l_hopcnt = 0;
            //int l_field = intuniform(0,1500);
            int l_field = 300;

            // 设置packet的属性
            outer_packet->setDst_x(dest_num_x);
            outer_packet->setDst_y(dest_num_y);
            outer_packet->setHopcnt(l_hopcnt);
            outer_packet->setField(l_field);

            return outer_packet;
        }
        // 有1 - ltr_rate的包落在任意节点
        else
        {
            // 和随机均匀的发送方式相同
            EV << "entering uniform_random" << endl;
            Packet *outer_packet = new Packet("outer_packet");
            outer_packet->setSend_time(simTime());

            int dst_random_int = intuniform(0,A_dies.size()-1);
            int dst_random_x = A_dies[dst_random_int][0];
            int dst_random_y = A_dies[dst_random_int][1];

            int l_hopcnt = 0;
            //int l_field = intuniform(0,1500);
            int l_field = 300;

            outer_packet->setSrc_x(self_x);
            outer_packet->setSrc_y(self_y);
            outer_packet->setDst_x(dst_random_x);
            outer_packet->setDst_y(dst_random_y);
            outer_packet->setHopcnt(l_hopcnt);
            outer_packet->setField(l_field);

            return outer_packet;
        }
    }
}

void Outer::refreshDisplay() const
{
    char buf[100];
    sprintf(buf, "rcvd: %ld \n sent: %ld", recv_packet_num, send_packet_num);
    getDisplayString().setTagArg("t", 0, buf);
}

